/**
 *
 *  @project Broadcast
 *  @author Toni Marquez
 *
 **/

/* INCLUDES */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <Winsock2.h>
#else
//linux
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define SOCKADDR sockaddr 
#endif

/* STRUCT */

struct Data {
  char primitiva[25];
  char game[25];
  char ip[16];
  int port;
};

Data g_client_data, g_server_data[5];

/* VARS */
#ifdef _WIN32
WSAData wsa;
SOCKET sock;
struct sockaddr_in ip;
int g_ip_size;
#else
int sock;
sockaddr_in ip;
socklen_t g_ip_size;
#endif

/* METHODS */

// init WSA, sockets & connection with server
void InitWSA(char** argv){

#ifdef _WIN32
  WSAStartup(MAKEWORD(2, 0), &wsa);
#endif
  sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  ip.sin_family = AF_INET;
  ip.sin_addr.s_addr = inet_addr(argv[1]);
  ip.sin_port = htons(atoi(argv[2]));

  g_ip_size = sizeof(ip);
}

// program engine
void Engine(){
  bool is_connected = false;

  // [1] send GDP_DISCOVERY
  memset(g_client_data.primitiva, 0, 25);
  strncpy(g_client_data.primitiva, "GDP_DISCOVERY\0", 14);
#ifdef _WIN32  
  sendto(sock, (char*)&g_client_data.primitiva, sizeof(g_client_data.primitiva), 0, (SOCKADDR*)&ip, g_ip_size);
#else
  sendto(sock, (char*)&g_client_data.primitiva, sizeof(g_client_data.primitiva), 0, (const sockaddr*)&ip, g_ip_size);
#endif  
  printf("discovering servers...\n\n");

  // [2] receive GDP_OFFER from 5 clients
  for (unsigned short int i = 1; i < 6; ++i){ //??? sizeof
#ifdef _WIN32  
    recvfrom(sock, (char*)&g_server_data[i], sizeof(g_server_data[i]), 0, (SOCKADDR*)&ip, &g_ip_size);
#else
    recvfrom(sock, (char*)&g_server_data[i], sizeof(g_server_data[i]), 0, (sockaddr*)&ip, &g_ip_size);
#endif
    printf("[%d] [%s] [%s]\n", i, g_server_data[i].ip, g_server_data[i].game);
  }

  do {
    // [2] send GDP_CONNECT
    printf("\nselect a server to connect: ");
    memset(g_client_data.game, 0, 25);
    gets(g_client_data.game);
    memset(g_client_data.primitiva, 0, 25);
    strncpy(g_client_data.primitiva, "GDP_CONNECT\0", 12);
    sendto(sock, (char*)&g_client_data, sizeof(g_client_data), 0, (SOCKADDR*)&ip, g_ip_size);
    printf("sent connection petition\n");

    memset(g_client_data.primitiva, 0, 25);
    recvfrom(sock, (char*)&g_client_data.primitiva, sizeof(g_client_data.primitiva), 0, (SOCKADDR*)&ip, &g_ip_size);

    // [3] receive GDP_ACK
    if (!strncmp(g_client_data.primitiva, "GDP_ACK", 7)){
      printf("connected to server\n");
      is_connected = true;
    }
    else if (!strncmp(g_client_data.primitiva, "GDP_ERROR", 9)){
      printf("ERROR, failed to connect to server, try again\n\n");
    }
  } while(!is_connected);
}

// close sockets & WSA
void CloseWSA(){
#ifdef _WIN32
  closesocket(sock);
  WSACleanup();
#else
  close(sock);
#endif  
}

// main
int main(int argc, char** argv){
  InitWSA(argv);
  Engine();
  CloseWSA();
  return 0;
}
